package org.duang.aop;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.duang.common.exceptios.ServiceException;
import org.duang.kit.LogKit;
import org.duang.kit.ObjectKit;
import org.duang.logs.Logger;

import net.sf.cglib.proxy.MethodProxy;

/**
 * 代理链
 */
public class ProxyChain {

	private static final Logger logger = LogKit.getLogger(ProxyChain.class);
	
    private final Class<?> targetClass;				// 被代理类
    private final Object targetObject;				// 被代理对象实例
    private final Method targetMethod;				// 被代理方法
    private final MethodProxy methodProxy;			// 代理后的方法
    private final Object[] methodParams;    		// 方法参数
	private static final Set<String> excludedMethodName = ObjectKit.buildExcludedMethodName();
	
    private List<Proxy> proxyList = new ArrayList<Proxy>();
    private int proxyIndex = 0;

    public ProxyChain(Class<?> targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List<Proxy> proxyList) {
        this.targetClass = targetClass;
        this.targetObject = targetObject;
        this.targetMethod = targetMethod;
        this.methodProxy = methodProxy;
        this.methodParams = methodParams;
        this.proxyList = proxyList;
    }

    public Object[] getMethodParams() {
        return methodParams;
    }
    
    public Class<?> getTargetClass() {
        return targetClass;
    }

    public Method getTargetMethod() {
        return targetMethod;
    }

    public Object doProxyChain() {
        Object methodResult = null;
        try {
        	//如有多个，按顺序重复执行
	        if (proxyIndex < proxyList.size()) {
	            methodResult = proxyList.get(proxyIndex++).doProxy(this);
	        } else {	           
	        		// 不执行Object类里的公共方法
	            	if(!excludedMethodName.contains(targetMethod.getName())) {			            		
	        			methodResult = methodProxy.invokeSuper(targetObject, methodParams);
	            	}			
	        }
        } catch (InvocationTargetException ite){
        	logger.print(ite.getMessage(), ite);
        	Throwable t = ite.getTargetException();
        	throw t instanceof RuntimeException ? (RuntimeException)t : new RuntimeException(ite);
        } catch (Throwable e) {
        	logger.print(e.getMessage(), e);
			throw new ServiceException(e).setMessage(e.getMessage()).setCode(500);
		}
        return methodResult;
    }
    
    public Object doProxyChain(Object[] params) throws Exception {
        Object methodResult = null;
            try {
            	// 不执行Object类里的公共方法
            	if(!excludedMethodName.contains(targetMethod.getName())) {		
        			methodResult = methodProxy.invokeSuper(targetObject, params);
            	}
			} catch (Throwable e) {
				logger.print(e.getMessage(), e);
				throw new ServiceException(e).setMessage(e.getMessage()).setCode(500);
			}
        return methodResult;
    }
    
}
